/**
 * Copyright (c) 2008, George Taylor
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted 
 * provided that the following conditions are met:
 * 
 *   * Redistributions of source code must retain the above copyright notice, this list of 
 *     conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice, this list of 
 *     conditions and the following disclaimer in the documentation and/or other materials 
 *     provided with the distribution.
 *   * Neither the name of the copyright holder's organization nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software without specific 
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package uk.co.taylorconsulting.annoweb.web.builder.data;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.log4j.Logger;

import uk.co.taylorconsulting.annoweb.annotation.action.Action;
import uk.co.taylorconsulting.annoweb.annotation.security.Role;
import uk.co.taylorconsulting.annoweb.annotation.web.DefaultForward;
import uk.co.taylorconsulting.annoweb.annotation.web.Forward;
import uk.co.taylorconsulting.annoweb.annotation.web.Web;

public class Site {
	private String                                name;
	private String                                contextClass;
	private String                                ext;
	private Globals                               globals;
	private HashMap<Class<?>, ArrayList<Role>>    roles           = new HashMap<Class<?>, ArrayList<Role>>();
	private HashMap<Class<?>, DefaultForward>     defaultForwards = new HashMap<Class<?>, DefaultForward>();
	private HashMap<Class<?>, ArrayList<Forward>> classForwards   = new HashMap<Class<?>, ArrayList<Forward>>();
	private String                                dispatch;
	private HashMap<String, ActionHolder>         actions         = new HashMap<String, ActionHolder>();
	private Method                                defaultAction;
	private static final Logger                   LOG             = Logger.getLogger(Site.class);
	
	public Site(String name, String contextClass) {
		this.name = name.toLowerCase();
		this.contextClass = contextClass;
	}
	
	public Site(String name, String contextClass, String ext) {
		this.name = name.toLowerCase();
		this.contextClass = contextClass;
		this.ext = ext;
	}
	
	public void setName(String name) {
		this.name = name.toLowerCase();
	}
	
	public void setContextClass(String contextClass) {
		this.contextClass = contextClass;
	}
	
	public void setExt(String ext) {
		this.ext = ext;
	}
	
	public void setGlobals(Globals globals) {
		this.globals = globals;
	}
	
	public void addRole(Role role, Class<?> thisClass) {
		ArrayList<Role> roleList = roles.get(thisClass);
		if (roleList == null) {
			roleList = new ArrayList<Role>();
			roles.put(thisClass, roleList);
		}
		roleList.add(role);
	}
	
	public void addDefaultForward(DefaultForward defaultForward, Class<?> thisClass) {
		if (!defaultForwards.containsKey(thisClass)) {
			defaultForwards.put(thisClass, defaultForward);
		}
	}
	
	public void addForward(Forward forward, Class<?> thisClass) {
		ArrayList<Forward> forwards = classForwards.get(thisClass);
		if (forwards == null) {
			forwards = new ArrayList<Forward>();
			classForwards.put(thisClass, forwards);
		}
		forwards.add(forward);
	}
	
	public void setWeb(Web a) {
		if (dispatch == null || dispatch.equalsIgnoreCase("dispatch")) {
			dispatch = a.dispatch();
		}
		name = a.view();
	}
	
	public void merge(Site tmp) {
		if (dispatch == null || dispatch.equalsIgnoreCase("dispatch")) {
			dispatch = tmp.dispatch;
		}
		for (Class<?> c : tmp.roles.keySet()) {
			if (roles.containsKey(c)) {
				roles.get(c).addAll(tmp.roles.get(c));
			} else {
				roles.put(c, tmp.roles.get(c));
			}
		}
		for (Class<?> c : tmp.defaultForwards.keySet()) {
			if (!defaultForwards.containsKey(c)) {
				defaultForwards.put(c, tmp.defaultForwards.get(c));
			}
		}
		for (Class<?> c : tmp.classForwards.keySet()) {
			if (classForwards.containsKey(c)) {
				classForwards.get(c).addAll(tmp.classForwards.get(c));
			} else {
				classForwards.put(c, tmp.classForwards.get(c));
			}
		}
		if (defaultAction == null) {
			defaultAction = tmp.defaultAction;
		}
		for (String s : tmp.actions.keySet()) {
			if (!actions.containsKey(s)) {
				ActionHolder ah = tmp.actions.get(s);
				ah.setSite(this);
				actions.put(s, ah);
			}
		}
	}
	
	public String getName() {
		return name;
	}
	
	public ActionHolder addAction(Action action, Method method) {
		if (!actions.containsKey(action.dispatch() + ":" + action.value())) {
			ActionHolder ah = new ActionHolder(action, method, this);
			actions.put(action.dispatch() + ":" + action.value(), ah);
			globals.addAction(method, ah);
			return ah;
		}
		return null;
	}
	
	public void setDefaultAction(Method defaultAction) {
		if (this.defaultAction == null) {
			this.defaultAction = defaultAction;
		}
	}
	
	public void addActionRole(Action action, Role role) {
		ActionHolder ah = actions.get(action.dispatch() + ":" + action.value());
		if (ah != null) {
			ah.addRole(role);
		}
	}
	
	public void addActionDefaultForward(DefaultForward forward, Action action) {
		ActionHolder ah = actions.get(action.dispatch() + ":" + action.value());
		if (ah != null) {
			ah.setDefaultForward(forward);
		}
	}
	
	public void addActionForward(Forward forward, Action action) {
		ActionHolder ah = actions.get(action.dispatch() + ":" + action.value());
		if (ah != null) {
			ah.addForward(forward);
		}
	}
	
	public void debug() {
		if (LOG.isDebugEnabled()) {
			StringBuffer str = new StringBuffer("Site -- ").append(name).append(" --\n");
			str.append("context class: ").append(contextClass).append("\n");
			str.append("ext:").append(ext).append("\n");
			str.append("Roles:\n");
			for (Class<?> c : roles.keySet()) {
				ArrayList<Role> rs = roles.get(c);
				for (Role r : rs) {
					str.append(r.value()).append(", realm=").append(r.realm()).append("\n");
				}
			}
			str.append("dispatch=").append(dispatch).append("\n");
			str.append("Default Forwards:\n");
			for (Class<?> c : defaultForwards.keySet()) {
				str.append(c.getCanonicalName()).append(":").append(defaultForwards.get(c).value()).append("\n");
			}
			str.append("Class Forwards:\n");
			for (Class<?> c : classForwards.keySet()) {
				str.append(c.getCanonicalName()).append("\n");
				for (Forward f : classForwards.get(c)) {
					str.append("  ").append(f.name()).append(", path=").append(f.path()).append(", web=").append(f.web().getCanonicalName()).append(", method=").append(f.method()).append(", redirect=").append(f.redirect()).append("\n");
				}
			}
			if (defaultAction == null) {
				str.append("defaultAction = null\n");
			} else {
				str.append("defaultAction =" + defaultAction.getDeclaringClass().getCanonicalName()).append(":").append(defaultAction.getName()).append("\n");
			}
			str.append("Actions:");
			for (String a : actions.keySet()) {
				ActionHolder ah = actions.get(a);
				str.append(ah.toString());
			}
			LOG.debug(str.toString());
		}
	}
	
	public HashMap<String, ActionHolder> getActions() {
		return actions;
	}
	
	public Method getDefaultAction() {
		return defaultAction;
	}
	
	public Globals getGlobals() {
		return globals;
	}
	
	public HashMap<Class<?>, ArrayList<Role>> getRoles() {
		return roles;
	}
	
	public HashMap<Class<?>, DefaultForward> getDefaultForwards() {
		return defaultForwards;
	}
	
	public HashMap<Class<?>, ArrayList<Forward>> getClassForwards() {
		return classForwards;
	}
	
	public String getDispatch() {
		return dispatch;
	}
	
	public ArrayList<Forward> getForward(Class<?> clazz) {
		ArrayList<Forward> retVal = classForwards.get(clazz);
		if (retVal == null) {
			retVal = new ArrayList<Forward>();
		}
		return retVal;
	}
	
	public String getExt() {
		return ext;
	}
}
